/*
 * Copyright (C) 2012 Amlogic Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <sys/types.h>
#include <sys/wait.h> 
#include <unistd.h>
#include <errno.h>

#include "install.h"
#include "cmd_excute.h"
#include "roots.h"
#include "common.h"

/**
 *  parser the command args:
 */ 
static int parser_cmd_args(char* cmd_str, int* arg_c,\
	 char** arg_v, int max_arg_num)
{
	int i = 0;
	char* arg_value;

	arg_value = strtok(cmd_str, " ");
    
	while(arg_value != NULL && i < max_arg_num) {
		arg_v[i++] = arg_value;  
		arg_value = strtok(NULL, " ");
	}
	*arg_c = i-1;

	return 0;
}
 
/**
 *  Recovery run linux command programming:
 */
int recovery_run_cmd(char* command_args)
{
	int result = INSTALL_SUCCESS;
	int arg_c = 0;
	char* arg_v[MAX_ARGS_NUM];
	memset(arg_v, 0, sizeof(char*) * MAX_ARGS_NUM);
	int status;
	char real_cmd_str[256];
	memset(real_cmd_str, 0, 256);
	
	if (ensure_path_mounted("/data") != 0) {
		LOGE("Can't mount 'data'\n");
	}

	if (ensure_path_mounted("/system") != 0) {
		LOGE("Can't mount 'system'\n");
	}

#ifdef RECOVERY_HAS_MEDIA
	if (ensure_path_mounted("/media") != 0)  {
		LOGE("Can't mount 'media'\n");
	}
#endif

	if (command_args[0] == '\"')
		strncpy(real_cmd_str, (char*)(&command_args[1]), \
				strlen(command_args));
       else
              strncpy(real_cmd_str, command_args, strlen(command_args));
	if (real_cmd_str[strlen(real_cmd_str) - 1] == '\"')
		real_cmd_str[strlen(real_cmd_str) - 1] = '\0';
	LOGI("command_args= %s\n", real_cmd_str);
	parser_cmd_args(real_cmd_str, &arg_c, arg_v, MAX_ARGS_NUM);

	pid_t pid = fork();
	if (pid == 0) {
		if (execv(arg_v[0], (char* const*)arg_v) < 0) {
			LOGE("E:Can't run command %s (%s)\n", 
				arg_v[0], strerror(errno));
			_exit(-1);
		}
		_exit(0);
	}
	
	waitpid(pid, &status, 0);
	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
		LOGE("Error in run command %s\n(Status %d)\n", 
			arg_v[0], WEXITSTATUS(status));
		result = INSTALL_ERROR;
	} else if (WIFSIGNALED(result)) {
		LOGE("command terminated (%d)\n", WTERMSIG(result));
		result = INSTALL_ERROR;
	}

	ensure_path_unmounted("/data");
	ensure_path_unmounted("/system");
#ifdef RECOVERY_HAS_MEDIA
	ensure_path_unmounted("/media");
#endif
	
	return result;
}


/****
 *  Recovery run linux command programming:
 *  usage:
 *  char *command="/sbin/fdisk.media.sh";
 *  ret = CmdRuner::run_command(command);
 *  ret =   0: successful.
 *  ret = -1: failed.
 ****/
int CmdRuner::run_command(char* command)
{
	int result = 0, argc = 0, i, j;
       pid_t pid = 0;
	char *argv[MAX_ARGS_NUM];
	char real_command[256];

       printf("run_command(%s)\n", command);
	memset(real_command, 0, 256);
    	memset(argv, 0, sizeof(char*) * MAX_ARGS_NUM);
       
       if(command[0] == '\"')
       {
            strncpy(real_command, command+1, strlen(command)-1);
            if(real_command[(strlen(real_command)-1)] == '\"')
                real_command[(strlen(real_command)-1)] = '\0';
        }
       else
            strncpy(real_command, command, strlen(command));
       printf("command=%s\n", real_command);
       
       parser_cmd_args(real_command, &argc, argv, MAX_ARGS_NUM);
       for(i=0; i<=argc; i++)
            printf("argv[%d]=%s\n", i, argv[i]);
       
       printf("start to execute %s ...\n", argv[0]); 

       pid = fork();
       if (pid == 0) {
             result = execv(argv[0], NULL);
             if (result)
                  LOGE("execute command: %s failed(%s)\n", argv[0], strerror(errno));
             _exit(-1);
       }
       waitpid(pid, &result, 0);
       if (WIFEXITED(result)) {
             if (WEXITSTATUS(result) != 0) {
                  LOGE("execute command: %s failed(%s)\n", argv[0], WEXITSTATUS(result));
                  result = -1;
             }
             else
                  result = 0;
       }
       else if (WIFSIGNALED(result)) {
             LOGE("execute command: %s terminated(%d)\n", argv[0], WTERMSIG(result));
             result = -1;
       }
       else
             result = 0;

       if(result)
       {
             printf("execute command: %s failed\n", argv[0]);
             goto error;
       }
       else
             printf("execute command: %s successful\n", argv[0]);
       
       usleep(1000);

error:
       return result;
}


/****
 *  Recovery run linux command programming:
 *  usage:
 *  char *command="/sbin/busybox";
 *  char *argv[]={"/sbin/busybox", "mkfs.vfat", "/dev/block/cache", NULL};
 *  ret = CmdRuner::run_command(command, argv);
 *  ret =   0: successful.
 *  ret = -1: failed.
 ****/
int CmdRuner::run_command(char* command, char **parameters)
{
	int result = 0, argc = 0, i;
       pid_t pid = 0;
	char *argv[MAX_ARGS_NUM];
	char real_command[256];

       printf("run_command(%s)\n", command);
	memset(real_command, 0, 256);
    	memset(argv, 0, sizeof(char*) * MAX_ARGS_NUM);

       if(command[0] == '\"')
       {
            strncpy(real_command, command+1, strlen(command)-1);
            if(real_command[(strlen(real_command)-1)] == '\"')
                real_command[(strlen(real_command)-1)] = '\0';
        }
       else
            strncpy(real_command, command, strlen(command));
       printf("command=%s\n", real_command);
       
       parser_cmd_args(real_command, &argc, argv, MAX_ARGS_NUM);
       for(i=0; i<=argc; i++)
            printf("argv[%d]=%s\n", i, argv[i]);
       
       printf("start to execute %s ...\n", argv[0]); 
       if(!strcmp(argv[0], "/sbin/busybox"))
       {
             printf("parameters is: ");
             for(i=0; i<=MAX_ARGS_NUM; i++)
             {
                   printf("%s ", parameters[i]);
                   if(parameters[i] == NULL)
                   {
                        printf("\n");
                        break;
                   }    
             }
       }    
      
       pid = fork();
       if (pid == 0) {
             result = execv(argv[0], parameters);
             if (result)
                  LOGE("execute command: %s failed(%s)\n", argv[0], strerror(errno));
             _exit(-1);
       }
       waitpid(pid, &result, 0);
       if (WIFEXITED(result)) {
             if (WEXITSTATUS(result) != 0) {
                  LOGE("execute command: %s failed(%s)\n", argv[0], WEXITSTATUS(result));
                  result = -1;
             }
             else
                  result = 0;
       }
       else if (WIFSIGNALED(result)) {
             LOGE("execute command: %s terminated(%d)\n", argv[0], WTERMSIG(result));
             result = -1;
       }
       else
             result = 0;

       if(result)
       {
             printf("execute command: %s failed\n", argv[0]);
             goto error;
       }
       else
             printf("execute command: %s successful\n", argv[0]);
       
       usleep(1000);

error:
       return result;
}